package com.fau.wmbj.server.service.impl;

import com.fau.wmbj.server.entity.Company;
import com.fau.wmbj.server.entity.Menu;
import com.fau.wmbj.server.entity.Role;
import com.fau.wmbj.server.entity.User;
import com.fau.wmbj.server.service.CompanyService;
import com.fau.wmbj.server.service.MenuService;
import com.fau.wmbj.server.service.RoleService;
import com.fau.wmbj.server.service.base.BaseServiceImpl;
import com.fau.wmbj.server.utils.Filter;
import com.fau.wmbj.server.utils.Order;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * 菜单
 *
 * @author jiawei
 * @version 1.0
 * @datetime 2024-02-27 10:03
 */
@Service
public class MenuServiceImpl extends BaseServiceImpl<Menu, Long> implements MenuService {

    @Resource
    @Lazy
    private RoleService roleService;

    @Resource
    @Lazy
    private CompanyService companyService;

    @Override
    public Map<String, Object> getUserMenus(User user) {
        if (user == null) {
            return null;
        }
        List<Menu> menus = new ArrayList<>(user.getRole().getMenus());
        Map<String, Object> result = new HashMap<>();
        List<Map<String, Object>> routes = new ArrayList<>();
        for (Menu menu : menus) {
            Map<String, Object> route = new HashMap<>();
            route.put("id", menu.getId());
            if (menu.getParent() != null) {
                route.put("pid", menu.getParent().getId());
            }
            route.put("path", menu.getPath());
            route.put("name", menu.getName());
            route.put("component", menu.getComponent());
            route.put("order", menu.getOrder());
            HashMap<Object, Object> metaInfo = new HashMap<>();
            metaInfo.put("title", menu.getTitle());
            metaInfo.put("icon", menu.getIcon());
            metaInfo.put("i18nKey", menu.getI18nKey());
            if (menu.getKeepAlive() != null) {
                metaInfo.put("keepAlive", menu.getKeepAlive());
            }
            if (menu.getHideInMenu() != null) {
                metaInfo.put("hideInMenu", menu.getHideInMenu());
            }
            if (menu.getActiveMenu() != null) {
                metaInfo.put("activeMenu", menu.getActiveMenu());
            }
            if (menu.getLocalIcon() != null) {
                metaInfo.put("localIcon", menu.getLocalIcon());
            }
            if (menu.getHref() != null) {
                metaInfo.put("href", menu.getHref());
            }
            if (menu.getMultiTab() != null) {
                metaInfo.put("multiTab", menu.getMultiTab());
            }
            if (menu.getFixedIndexInTab() != null) {
                metaInfo.put("fixedIndexInTab", menu.getFixedIndexInTab());
            }
            route.put("meta", metaInfo);
            routes.add(route);
        }
        List<Map<String, Object>> tree = listToTree(routes);
        result.put("routes", tree);
        result.put("home", "workbench");
        return result;
    }

    @Override
    public Map<String, Object> getAllMenus() {
        Map<String, Object> result = new HashMap<>();
        List<Order> orderList = new ArrayList<>();
        orderList.add(Order.asc("order"));
        List<Filter> filterList = new ArrayList<>();
        filterList.add(Filter.isNull("parent"));
        List<Menu> menus = super.findList(null, filterList, orderList);
        List<Map<String, Object>> routes = new ArrayList<>();
        for (Menu menu : menus) {
            Map<String, Object> route = new HashMap<>();
            route.put("id", menu.getId());
            route.put("pid", menu.getParent() != null ? menu.getParent().getId() : null);
            route.put("path", menu.getPath());
            route.put("name", menu.getName());
            route.put("component", menu.getComponent());
            route.put("order", menu.getOrder());
            HashMap<Object, Object> metaInfo = new HashMap<>();
            metaInfo.put("title", menu.getTitle());
            metaInfo.put("icon", menu.getIcon());
            metaInfo.put("i18nKey", menu.getI18nKey());
            if (menu.getKeepAlive() != null) {
                metaInfo.put("keepAlive", menu.getKeepAlive());
            }
            if (menu.getHideInMenu() != null) {
                metaInfo.put("hideInMenu", menu.getHideInMenu());
            }
            if (menu.getActiveMenu() != null) {
                metaInfo.put("activeMenu", menu.getActiveMenu());
            }
            if (menu.getLocalIcon() != null) {
                metaInfo.put("localIcon", menu.getLocalIcon());
            }
            if (menu.getHref() != null) {
                metaInfo.put("href", menu.getHref());
            }
            if (menu.getMultiTab() != null) {
                metaInfo.put("multiTab", menu.getMultiTab());
            }
            if (menu.getFixedIndexInTab() != null) {
                metaInfo.put("fixedIndexInTab", menu.getFixedIndexInTab());
            }

            route.put("meta", metaInfo);
            routes.add(route);
        }
        List<Map<String, Object>> tree = listToTree(routes);
        result.put("routes", tree);
        result.put("home", "home");
        return result;
    }

    @Override
    public List<Map<String, Object>> getRoleMenus(Long roleId) {
        Role role = roleService.find(roleId);
        Set<Menu> menus = role.getMenus();
        List<Map<String, Object>> routes = new ArrayList<>();
        for (Menu menu : menus) {
            Map<String, Object> route = new HashMap<>();
            route.put("id", menu.getId());
            route.put("pid", menu.getParent() != null ? menu.getParent().getId() : null);
            route.put("path", menu.getPath());
            route.put("name", menu.getName());
            route.put("component", menu.getComponent());
            route.put("order", menu.getOrder());
            HashMap<Object, Object> metaInfo = new HashMap<>();
            metaInfo.put("title", menu.getTitle());
            metaInfo.put("icon", menu.getIcon());
            metaInfo.put("i18nKey", menu.getI18nKey());
            if (menu.getKeepAlive() != null) {
                metaInfo.put("keepAlive", menu.getKeepAlive());
            }
            if (menu.getHideInMenu() != null) {
                metaInfo.put("hideInMenu", menu.getHideInMenu());
            }
            if (menu.getActiveMenu() != null) {
                metaInfo.put("activeMenu", menu.getActiveMenu());
            }
            if (menu.getLocalIcon() != null) {
                metaInfo.put("localIcon", menu.getLocalIcon());
            }
            if (menu.getHref() != null) {
                metaInfo.put("href", menu.getHref());
            }
            if (menu.getMultiTab() != null) {
                metaInfo.put("multiTab", menu.getMultiTab());
            }
            if (menu.getFixedIndexInTab() != null) {
                metaInfo.put("fixedIndexInTab", menu.getFixedIndexInTab());
            }

            route.put("meta", metaInfo);
            routes.add(route);
        }
        return listToTree(routes);
    }

    @Override
    public List<Map<String, Object>> getCompanyMenus(Long companyId) {
        Company company = companyService.find(companyId);
        Set<Menu> menus = company.getMenus();
        List<Map<String, Object>> routes = new ArrayList<>();
        for (Menu menu : menus) {
            Map<String, Object> route = new HashMap<>();
            route.put("id", menu.getId());
            route.put("pid", menu.getParent() != null ? menu.getParent().getId() : null);
            route.put("path", menu.getPath());
            route.put("name", menu.getName());
            route.put("component", menu.getComponent());
            route.put("order", menu.getOrder());
            HashMap<Object, Object> metaInfo = new HashMap<>();
            metaInfo.put("title", menu.getTitle());
            metaInfo.put("icon", menu.getIcon());
            metaInfo.put("i18nKey", menu.getI18nKey());
            if (menu.getKeepAlive() != null) {
                metaInfo.put("keepAlive", menu.getKeepAlive());
            }
            if (menu.getHideInMenu() != null) {
                metaInfo.put("hideInMenu", menu.getHideInMenu());
            }
            if (menu.getActiveMenu() != null) {
                metaInfo.put("activeMenu", menu.getActiveMenu());
            }
            if (menu.getLocalIcon() != null) {
                metaInfo.put("localIcon", menu.getLocalIcon());
            }
            if (menu.getHref() != null) {
                metaInfo.put("href", menu.getHref());
            }
            if (menu.getMultiTab() != null) {
                metaInfo.put("multiTab", menu.getMultiTab());
            }
            if (menu.getFixedIndexInTab() != null) {
                metaInfo.put("fixedIndexInTab", menu.getFixedIndexInTab());
            }

            route.put("meta", metaInfo);
            routes.add(route);
        }
        return listToTree(routes);
    }

    @Override
    public void updateMenu(Menu menu) {
        Long id = menu.getId();
        Map<String, Object> meta = menu.getMeta();
        String icon = (String) meta.get("icon");
        String title = (String) meta.get("title");
        String href = (String) meta.get("href");
        Menu before = super.find(id);
        if (StringUtils.isNotBlank(icon)) {
            before.setIcon(icon);
        }
        if (StringUtils.isNotBlank(href)) {
            before.setHref(href);
        }
        if (StringUtils.isNotBlank(title)) {
            before.setTitle(title);
        }
        super.update(before);

    }

    // 递归将list转换为tree
    private List<Map<String, Object>> listToTree(List<Map<String, Object>> list) {
        List<Map<String, Object>> rootList = new ArrayList<>();
        for (Map<String, Object> stringObjectMap : list) {
            if (stringObjectMap.get("pid") == null) {
                rootList.add(stringObjectMap);
            }
        }
        findChildren(rootList, list);
        return rootList;
    }

    // 递归查找子节点
    private void findChildren(List<Map<String, Object>> list, List<Map<String, Object>> treeList) {
        for (Map<String, Object> stringObjectMap : list) {
            List<Map<String, Object>> children = new ArrayList<>();
            for (Map<String, Object> map : treeList) {
                if (stringObjectMap.get("id").equals(map.get("pid"))) {
                    children.add(map);
                }
            }
            if (!children.isEmpty()) {
                stringObjectMap.put("children", children);
            }
            if (stringObjectMap.get("children") != null && ((List<?>) stringObjectMap.get("children")).size() > 0) {
                findChildren(children, treeList);
            }
        }
    }
}
